#pragma once

#include <cstdio>
#include <ctime>
#include <istream>
#include <ostream>

namespace TableBase {

inline size_t FromStream7BitEncodedInt(std::istream &stream) {
    size_t value = 0;
    int count = 0;
    while (true) {
        unsigned char byte;
        stream.read((char *)&byte, 1);
        value += size_t(byte & 0x7f) << (count++ * 7);
        if (byte <= 0x7f) {
            break;
        }
    }
    return value;
}

inline void ToStream7BitEncodedInt(size_t value, std::ostream &stream) {
    unsigned char buffer[10];
    size_t count = 0;
    while (true) {
        int flag = value > 0x7f ? 0x80 : 0;
        buffer[count++] = (unsigned char)(flag | value);
        if (flag > 0) {
            value >>= 7;
        } else {
            break;
        }
    }
    stream.write((const char *)buffer, count);
}

inline time_t FromStringDateTime(const char *s) {
    if (s == nullptr || *s == '\0') {
        return -1;
    }
    struct tm tm;
    int n = sscanf(s, "%d-%d-%d %d:%d:%d", &tm.tm_year, &tm.tm_mon,
        &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
    if (n != 6) {
        return -1;
    }
    tm.tm_year -= 1900;
    tm.tm_mon -= 1;
    tm.tm_isdst = 0;
    return mktime(&tm);
}

inline std::string ToStringDateTime(time_t t) {
    if (t == -1) {
        return {};
    }
    struct tm tm;
#if defined(_WIN32)
    if (localtime_s(&tm, &t) != 0) {
#else
    if (localtime_r(&t, &tm) == nullptr) {
#endif
        return {};
    }
    char s[32];
    size_t n = strftime(s, sizeof(s), "%Y-%m-%d %H:%M:%S", &tm);
    if (n == 0) {
        return {};
    }
    return {s, n};
}

inline int FromStringTime(const char *s) {
    if (s == nullptr || *s == '\0') {
        return -1;
    }
    int hour, min, sec;
    int n = sscanf(s, "%d:%d:%d", &hour, &min, &sec);
    if (n != 3) {
        return -1;
    }
    return hour*3600 + min*60 + sec;
}

inline std::string ToStringTime(int t) {
    if (t == -1) {
        return {};
    }
    char s[16];
    size_t n = snprintf(s, sizeof(s), "%d:%d:%d", t/3600, t%3600/60, t%60);
    if (n >= sizeof(s)) {
        return {};
    }
    return {s, n};
}

inline void FromStringDateTime(int64 t, const std::string_view &s) {
    t = FromStringDateTime(s.data());
}

inline void FromStringTime(int32 t, const std::string_view &s) {
    t = FromStringTime(s.data());
}

}
